using System;
using System.Reflection;
using NUnit.Framework;
using ValidationFramework.Reflection;
#if (!SILVERLIGHT && !WindowsCE)
using ValidationFramework.Web.ASP;
#endif

namespace ValidationFramework.Tests
{
    public class CompareStructRuleTest
    {
        private const string expectedErrorMessage = "expectedErrorMessage";
        private const string expectedRuleSet = "EXPECTEDRULESET";
        private const int expectedValueToCompare = 2;
        private const CompareOperator expectedCompareOperator = CompareOperator.GreaterThan;

        [TestFixture]
        public class Construction
        {
            [Test]
            public void Simple1()
            {
                var rule = new CompareRule<int>(expectedErrorMessage, false, expectedValueToCompare, expectedCompareOperator);
                Assert.AreEqual(expectedErrorMessage, rule.ErrorMessage);
                Assert.AreEqual(expectedValueToCompare, rule.ValueToCompare);
                Assert.AreEqual(expectedCompareOperator, rule.CompareOperator);
                Assert.IsFalse(rule.UseErrorMessageProvider);
            }


            [Test]
            public void ExceptionInvalidCompareOperator1()
            {
                Exception argException = null;
                try
                {
                    var constructor = typeof(CompareRule<int>).GetConstructor(new[] { typeof(string), typeof(bool), typeof(int), typeof(CompareOperator) });
                    constructor.Invoke(new object[] { expectedErrorMessage, false, expectedValueToCompare, -1 });
                }
                catch (TargetInvocationException e)
                {
                    argException = e.InnerException;
                }
                Assert.IsNotNull(argException);
            }

            [Test]
            [ExpectedException(typeof(ArgumentNullException), ExpectedMessage = "Value cannot be null.\r\nParameter name: valueToCompare")]
            public void ExceptionValueToCompareNull1()
            {
                new CompareRule<string>(expectedErrorMessage, false, null, expectedCompareOperator);
            }


            [Test]
            public void Simple2()
            {
                var rule = new CompareRule<int>(expectedErrorMessage, expectedValueToCompare, expectedCompareOperator);
                Assert.AreEqual(expectedValueToCompare, rule.ValueToCompare);
                Assert.AreEqual(expectedCompareOperator, rule.CompareOperator);
                Assert.AreEqual(expectedErrorMessage, rule.ErrorMessage);
                Assert.IsFalse(rule.UseErrorMessageProvider);
            }


            [Test]
            public void ExceptionInvalidCompareOperator2()
            {
                Exception argException = null;
                try
                {

                    var constructor = typeof(CompareRule<int>).GetConstructor(new[] { typeof(string), typeof(int), typeof(CompareOperator) });
                    constructor.Invoke(new object[] { expectedErrorMessage, expectedValueToCompare, -1 });
                }
                catch (TargetInvocationException e)
                {
                    argException = e.InnerException;
                }
                Assert.IsNotNull(argException);
            }

            [Test]
            [ExpectedException(typeof(ArgumentNullException), ExpectedMessage = "Value cannot be null.\r\nParameter name: valueToCompare")]
            public void ExceptionValueToCompareNull2()
            {
                new CompareRule<string>(expectedErrorMessage, null, expectedCompareOperator);
            }


            [Test]
            public void Simple3()
            {
                var rule = new CompareRule<int>(expectedValueToCompare, expectedCompareOperator);
                Assert.AreEqual(expectedValueToCompare, rule.ValueToCompare);
                Assert.AreEqual(expectedCompareOperator, rule.CompareOperator);
                Assert.IsNull(rule.ErrorMessage);
                Assert.IsFalse(rule.UseErrorMessageProvider);
            }


            [Test]
            public void ExceptionInvalidCompareOperator3()
            {
                Exception argException = null;
                try
                {
                    var constructor = typeof(CompareRule<int>).GetConstructor(new Type[] { typeof(int), typeof(CompareOperator) });
                    constructor.Invoke(new object[] { expectedValueToCompare, -1 });
                }
                catch (TargetInvocationException e)
                {
                    argException = e.InnerException;
                }
                Assert.IsNotNull(argException);
            }


            [Test]
            [ExpectedException(typeof(ArgumentNullException), ExpectedMessage = "Value cannot be null.\r\nParameter name: valueToCompare")]
            public void ExceptionValueToCompareNull3()
            {
                new CompareRule<string>(null, expectedCompareOperator);
            }

        }

        [TestFixture]
        public class IsEquivalent
        {
            [Test]
            public void Simple()
            {
                var rule1 = new CompareRule<int>(null, false, 5, CompareOperator.LessThan);
                var rule2 = new CompareRule<int>(null, false, 5, CompareOperator.LessThan);
                Assert.IsTrue(rule1.IsEquivalent(rule2));
                rule2 = new CompareRule<int>(null, false, 5, CompareOperator.GreaterThan);

                Assert.IsFalse(rule1.IsEquivalent(rule2));

            }

        }
        [TestFixture]
        public class Validate
        {
            [Test]
            public void Nullable()
            {
                const int expectedValueToCompare = 2;
                var rule = new CompareRule<int>(null, false, expectedValueToCompare, CompareOperator.GreaterThan);
                           		rule.CheckType(new MockInfoDescriptor(typeof(int?).TypeHandle, "foo"));
                Assert.IsNull(rule.Validate(null, null, null, null));
                Assert.IsNotNull(rule.Validate(null, 1, null, null));
                Assert.IsNotNull(rule.Validate(null, 2, null, null));
                Assert.IsNull(rule.Validate(null, 3, null, null));
            }

        [Test]
        public void ValidateNotNullable()
        {
            var rule = new CompareRule<int>(null, false, expectedValueToCompare, CompareOperator.GreaterThan);
            rule.CheckType(new MockInfoDescriptor(TypePointers.IntTypeHandle, "foo"));
            Assert.IsNotNull(rule.Validate(null, 1, null, null));
            Assert.IsNotNull(rule.Validate(null, 2, null, null));
            Assert.IsNull(rule.Validate(null, 3, null, null));
        }

        }
        
#if (!WindowsCE && !SILVERLIGHT)
        [TestFixture]
        public class GetBaseValidator
        {
            [Test]
            public void Unknown()
            {
                var rule = new CompareRule<fooStruct>(null, false, new fooStruct(), CompareOperator.GreaterThan);
                var infoDescriptor = new MockInfoDescriptor(typeof (fooStruct).TypeHandle, "foo");
                var ruleContext = new RuleContext {Rule = rule, InfoDescriptor = infoDescriptor};
                Assert.IsNull(BaseValidatorGenerator.Strategies.FindStrategy(ruleContext));   
            }

        [Test]
        public void NonDateTime()
        {
            var rule = new CompareRule<int>(null, false, expectedValueToCompare, CompareOperator.GreaterThan);
            var infoDescriptor = new MockInfoDescriptor(TypePointers.IntTypeHandle, "foo");
            var ruleContext = new RuleContext {Rule = rule, InfoDescriptor = infoDescriptor};
            var list = BaseValidatorGenerator.Strategies.FindStrategy(ruleContext).CreateWebClientValidators(rule, infoDescriptor);
            Assert.IsNotNull(list);
            Assert.AreEqual(1, list.Count);
        }


        [Test]
        public void Date()
        {
            var rule = new CompareRule<DateTime>(null, false, new DateTime(2007, 1, 1), CompareOperator.GreaterThan);
            var infoDescriptor = new MockInfoDescriptor(typeof (DateTime).TypeHandle, "foo");
            rule.CheckType(infoDescriptor);

            var ruleContext = new RuleContext {Rule = rule, InfoDescriptor = infoDescriptor};

            var list = BaseValidatorGenerator.Strategies.FindStrategy(ruleContext).CreateWebClientValidators(rule, infoDescriptor);
            Assert.IsNotNull(list);
            Assert.AreEqual(1, list.Count);
        }


        [Test]
        public void DateTime()
        {
            var rule = new CompareRule<DateTime>(null, false, new DateTime(2007, 1, 1, 2, 1, 1), CompareOperator.GreaterThan);
            var infoDescriptor = new MockInfoDescriptor(typeof (DateTime).TypeHandle, "foo");

            var ruleContext = new RuleContext {Rule = rule, InfoDescriptor = infoDescriptor};
            var list = BaseValidatorGenerator.Strategies.FindStrategy(ruleContext).CreateWebClientValidators(rule, infoDescriptor);
            Assert.IsNull(list);
        }

        }
#endif
        [TestFixture]
        public class RuleInterpretation
        {

            [Test]
            public void Simple()
            {
                var rule = new CompareRule<int>(null, false, expectedValueToCompare, CompareOperator.GreaterThan);
                Assert.IsFalse(string.IsNullOrEmpty(rule.RuleInterpretation));
            }
        }

        [TestFixture]
        public class CheckTypes
        {


            [Test]
            public void Simple()
            {
                var structRule = new CompareRule<DateTime>(null, false, DateTime.Now, CompareOperator.GreaterThan);
                structRule.CheckType(new MockInfoDescriptor(typeof (DateTime).TypeHandle, "foo"));
                var nullableRule = new CompareRule<DateTime>(null, false, DateTime.Now, CompareOperator.GreaterThan);
                nullableRule.CheckType(new MockInfoDescriptor(typeof (DateTime).TypeHandle, "foo"));
				nullableRule.CheckType(new MockInfoDescriptor(typeof(DateTime?).TypeHandle, "foo"));
            }


            [Test]
            [ExpectedException(typeof(ArgumentException), ExpectedMessage = "Member 'foo' must be a 'System.DateTime' to be used for the ValidationFramework.CompareRule<System.DateTime>. Actual Type 'System.Int32'.\r\nParameter name: value")]
            public void ExceptionInvalidType()
            {
                var rule = new CompareRule<DateTime>(null, false, DateTime.Now, CompareOperator.GreaterThan);
                rule.CheckType(new MockInfoDescriptor(TypePointers.IntTypeHandle, "foo"));
            }
        }

        struct fooStruct : IComparable<fooStruct>
        {


            public int CompareTo(fooStruct other)
            {
                throw new NotImplementedException();
            }
        }
    }
}